package com.example.learningspringboot.redis.config;

import io.lettuce.core.ClientOptions;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
public class RedisConfig {

    // 1. 添加 ClientResources bean (关键修复)
    @Bean(destroyMethod = "shutdown")
    public ClientResources clientResources() {
        return DefaultClientResources.create();
    }

    /**
     * Redis的模板(工具类)
     * RedisTemplate中配置自定义的RedisTemplate
     */
    @Bean("objectStringRedisTemplate")
    public RedisTemplate<String, Object> objectStringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 关键点2：必须配置序列化器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        // 关键点3：必须调用 afterPropertiesSet
        redisTemplate.afterPropertiesSet();
        return  redisTemplate;
    }

    /**
     * Redis的模板(工具类)
     * RedisTemplate中配置StringRedisTemplate
     */
    @Bean("stringRedisTemplate")
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
            StringRedisTemplate redisTemplate = new StringRedisTemplate();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            // 关键点2：必须配置序列化器
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
            // 关键点3：必须调用 afterPropertiesSet
            redisTemplate.afterPropertiesSet();
            return  redisTemplate;
    }

    /**
     * Redis的连接工厂, 这里也把Lettuce配置好了，
     * Lettuce 是一个高性能、全异步的 Java Redis 客户端，专为现代高并发场景设计。它基于 Netty 框架构建，支持同步、异步和反应式编程模型，
     * 是 Spring 生态中广泛采用的 Redis 驱动框架
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory(ClientResources clientResources) {
        RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration();
        serverConfig.setPassword("Nan123456");
        serverConfig.setPort(6379);
        serverConfig.setDatabase(0);
        serverConfig.setHostName("localhost");

        // 2. 连接池配置
        GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
        poolConfig.setMaxTotal(20);            // 最大连接数
        poolConfig.setMaxIdle(10);             // 最大空闲连接
        poolConfig.setMinIdle(5);              // 最小空闲连接
        poolConfig.setMaxWait(Duration.ofMillis(2000)); // 获取连接最大等待时间
        poolConfig.setTestOnBorrow(true);      // 借用连接时测试有效性
        poolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(30)); // 空闲检查周期
        // 3. Lettuce客户端配置
        LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .poolConfig(poolConfig)
                .clientResources(clientResources)
                .clientOptions(ClientOptions.builder()
                        .autoReconnect(true)       // 自动重连
                        .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
                        .build())
                .commandTimeout(Duration.ofSeconds(5)) // 命令超时
                .shutdownTimeout(Duration.ofMillis(100)) // 关闭超时
                .build();
        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(serverConfig, clientConfig);
        lettuceConnectionFactory.afterPropertiesSet();  // 关键：初始化连接工厂
        return lettuceConnectionFactory;
    }

//    private ClientOptions createClientOptions() {
//        return ClientOptions.builder()
//                .autoReconnect(true)
//                .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
//                .socketOptions(io.lettuce.core.SocketOptions.builder()
//                        .connectTimeout(Duration.ofSeconds(3))
//                        .build())
//                .build();
//    }



//    /**
//     * 配置自定义RedisTemplate
//     * @param factory Redis连接工厂
//     * @return 自定义RedisTemplate实例
//     */
//    @Bean
//    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
//        RedisTemplate<String, Object> template = new RedisTemplate<>();
//        template.setConnectionFactory(factory);
//
//        // 使用Jackson2JsonRedisSerializer来序列化value
//        GenericJackson2JsonRedisSerializer jacksonSerializer =
//                new GenericJackson2JsonRedisSerializer();
//
//        // String序列化器用于key
//        StringRedisSerializer stringSerializer = new StringRedisSerializer();
//
//        // key采用String序列化
//        template.setKeySerializer(stringSerializer);
//        template.setHashKeySerializer(stringSerializer);
//
//        // value采用Jackson序列化
//        template.setValueSerializer(jacksonSerializer);
//        template.setHashValueSerializer(jacksonSerializer);
//
//        template.afterPropertiesSet();
//        return template;
//    }

}
